using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Db4objects.Db4o;
using Db4objects.Db4o.Linq;
using SharedObjects;

namespace TheGameDatabaseTool
{
	public partial class DatabaseMainScript
	{
		public event EventHandler OperationCompleted;
		private readonly Db _database; //the central db server
		public readonly IObjectContainer Db; //the local client, connection always on during world activity
		private DateTime _worldTime = new DateTime(2012,1,1,0,0,0);
		private List<string> _lastNames;
		private List<string> _femFirstnames;
		private List<string> _maleFirstnames;
		private readonly List<Person> _usedNames;
		Dictionary<string, Guid> _corpNamesWithGuid;
		Dictionary<ulong, List<Guid>> _corporationIdToComputersystemId;
		private CoordinateCoordinator _coordinator;
		private Random _seeder;

		public DatabaseMainScript(bool recreate)
		{
			_database = new Db();
			if (recreate)
				_database.RecreateDatabase();
			Db = _database.ObtainClient();
			_lastNames = new List<string>();
			_femFirstnames = new List<string>();
			_maleFirstnames = new List<string>();
			_usedNames = new List<Person>();
			InitializeNameLists();
		}

		public void Testing()
		{
#pragma warning disable 168
			var entities = (from EntityBase b in Db select b).ToList();
			var accounts = (from ComputerSystemAccount a in Db select a).ToList();
			var files = (from SystemFile f in Db select f).ToList();
			var directories = (from SystemDirectory d in Db select d).ToList();			
			var result = (from ComputerSystem cs in Db select cs).ToList();
			int num = result.Count;
#pragma warning restore 168
		}

		public void Close()
		{
			Db.Close();
			_database.Close();
		}

		public void CreateWorld()
		{
			Stopwatch sw = new Stopwatch();
			sw.Start();
			WorldData wd = (from WorldData w in Db select w).FirstOrDefault();
			if (wd == null)
			{
				wd = new WorldData {Id = Guid.NewGuid().ToLong(), WorldTime = _worldTime, LastStartup = DateTime.Now};
			}
			else
			{
				_worldTime = wd.WorldTime;
				wd.LastStartup = DateTime.Now;
			}
			Db.Store(wd);

			_coordinator = new CoordinateCoordinator();

			#region Create all TLDs
			Tld tldCorp = GetEntity<Tld>(new Guid("55C42AFE-0B2F-4A0F-9F24-D3B26EDEBE8C").ToLong());
			tldCorp.Name = "Corp";
			Tld tldInc = GetEntity<Tld>(new Guid("A89CB488-767D-48C8-87B8-5C5E76D64732").ToLong());
			tldInc.Name = "Inc";
			Tld tldLtd = GetEntity<Tld>(new Guid("6400459E-91C8-4B31-B13F-D47D98CBB283").ToLong());
			tldLtd.Name = "Ltd";
			Tld tldGmbh = GetEntity<Tld>(new Guid("B468A7DE-86E3-48CE-BE7E-3590746232E4").ToLong());
			tldGmbh.Name = "PLC";
			Tld tldAg = GetEntity<Tld>(new Guid("BFCD8C6E-6E90-45E2-8A49-ADF70AAE0814").ToLong());
			tldAg.Name = "LLC";
			Tld tldBv = GetEntity<Tld>(new Guid("5E53A4CC-62F8-4AA1-B71A-ACEF374DA50D").ToLong());
			tldBv.Name = "Gen";
			Tld tldGov = GetEntity<Tld>(new Guid("E207E334-24E9-484C-BFA5-042A3501C9A7").ToLong());
			tldGov.Name = "Gov";
			Db.PersistEntity(tldGov);
			#endregion

			#region Create all Corporations
			Random rand = new Random(Environment.TickCount);
			List<Corporation> corps = new List<Corporation>();
			foreach (var corpName in _corpNamesWithGuid)
			{
				Corporation corporation = GetEntity<Corporation>(corpName.Value.ToLong());
				corporation.Name = corporation.Name ?? corpName.Key;
				corporation.DifficultyModifier = corporation.DifficultyModifier == 0 ? rand.Next(1, 6) : corporation.DifficultyModifier;
				//new Corporation { ID = Guid.NewGuid().ToLong(), Name = corpName };)
				if (corporation.TopLevelDomain == null)
				{
					int perc = rand.Next(1, 100);
					if (perc.Between(0, 11))
						corporation.TopLevelDomain = tldCorp;
					if (perc.Between(12, 24))
						corporation.TopLevelDomain = tldInc;
					if (perc.Between(25, 36))
						corporation.TopLevelDomain = tldLtd;
					if (perc.Between(37, 49))
						corporation.TopLevelDomain = tldInc;
					if (perc.Between(50, 61))
						corporation.TopLevelDomain = tldGmbh;
					if (perc.Between(62, 74))
						corporation.TopLevelDomain = tldAg;
					if (perc.Between(75, 86))
						corporation.TopLevelDomain = tldBv;
					if (perc.Between(86, 100))
						corporation.TopLevelDomain = tldCorp;
				}
				corps.Add(corporation);
				Db.PersistEntity(corporation);
			}
			corps.First().IsDefault = true;
			Db.PersistEntity(corps.First());

			Corporation adminCorp = GetEntity<Corporation>(new Guid("EADC8CE5-376B-471E-90F3-5CE7FD6DC08B").ToLong());
			adminCorp.IsDefault = false;
			adminCorp.IsDeleted = false;
			adminCorp.Name = "Administration";
			adminCorp.TopLevelDomain = tldInc;
			Db.PersistEntity(adminCorp);
			#endregion

			#region Create all program categories

			ProgramCategory pcatSecurity = GetEntity<ProgramCategory>(new Guid("79B6132D-65F6-48F9-AF92-3D2378367321").ToLong());
			pcatSecurity.Name = pcatSecurity.Name ?? "Security";
			Db.PersistEntity(pcatSecurity);

			ProgramCategory pcatFilesystem = GetEntity<ProgramCategory>(new Guid("B1A84548-64ED-4FBA-BDA2-1CB575BA1028").ToLong());
			pcatFilesystem.Name = pcatFilesystem.Name ?? "File system";
			Db.PersistEntity(pcatFilesystem);

			ProgramCategory pcatLogging = GetEntity<ProgramCategory>(new Guid("8E7B7625-275D-43AC-B93C-8542DCAC2C58").ToLong());
			pcatLogging.Name = pcatLogging.Name ?? "Logging";
			Db.PersistEntity(pcatFilesystem);

			#endregion

			#region security systems

			_ssUsernamePassword = CreateSecuritySystem(new Guid("{F869071A-51D0-4c0a-A851-F289BF2549A4}").ToLong(), "Username/Password", CredentialType.UsernamePassword, 1, 5, "AccessUsernamePassword", 1, true);
			Db.PersistEntity(_ssUsernamePassword);

			_ssFingerprintAuthentication = CreateSecuritySystem(new Guid("{40178257-45EB-450f-BE88-F2B99BE0286B}").ToLong(), "Fingerprint Authentication", CredentialType.Fingerprint, 2, 10, "AccessFingerPrint", 1, true);
			Db.PersistEntity(_ssFingerprintAuthentication);

			_ssRetinalScan = CreateSecuritySystem(new Guid("{678E641A-9A89-4701-9654-2A39155430E0}").ToLong(), "Retinal Scan Authentication", CredentialType.Retinal, 3, 15, "AccessRetinalScan", 1, true);
			Db.PersistEntity(_ssRetinalScan);

			_ssDna = CreateSecuritySystem(new Guid("{32DBE7FE-8F7E-4c4f-9860-94337C11CEC1}").ToLong(), "DNA Profile Authentication", CredentialType.Dna, 4, 20, "AccessDnaProfile", 1, true);
			Db.PersistEntity(_ssDna);

			_ssPsec = CreateSecuritySystem(new Guid("{571E7C07-39B5-4292-8A65-3C5E518E1625}").ToLong(), "Phase shifting elliptic curve", CredentialType.Psec, 5, 30, "AccessPSEC", 1, true);
			Db.PersistEntity(_ssPsec);

			_ssTbpa = CreateSecuritySystem(new Guid("{5BBCF2A5-2B04-4434-8466-966E05E05326}").ToLong(), "Timed Brain Pattern Analysis", CredentialType.Tbpa, 6, 120, "AccessTBPA", 1, true);

			#endregion

			#region System Features

			_csfFileView = CreateSystemFeature(new Guid("{4B8BE4AF-D6D8-416c-B98E-7330786F1530}").ToLong(), "File system", true, true);
			Db.PersistEntity(_csfFileView);

			_csfLogView = CreateSystemFeature(new Guid("{4EF4C236-230B-4ad2-8CA2-7CFF89093010}").ToLong(), "Log viewer", false, true);
			Db.PersistEntity(_csfLogView);

			_csfChat = CreateSystemFeature(new Guid("{AEE5CE77-E853-42a9-8857-15DA4837F4F9}").ToLong(), "Local chat", false, true);
			Db.PersistEntity(_csfChat);

			_csfEmail = CreateSystemFeature(new Guid("{8675C4C5-0EB1-445c-AA42-57F10B8F9D8C}").ToLong(), "Mail system", false, true);
			Db.PersistEntity(_csfEmail);

			_csfMarket = CreateSystemFeature(new Guid("{712EB328-67BE-4C5C-A5FC-24B50EFB0A1C}").ToLong(), "Market", false, true);
			Db.PersistEntity(_csfMarket);

			_csfBanking = CreateSystemFeature(new Guid("{F2DB69C0-1B0B-4734-8235-A145AF3590EF}").ToLong(), "Banking", false, true);
			Db.PersistEntity(_csfBanking);

			_csfPublicInfo = CreateSystemFeature(new Guid("{7C8B17B9-AB3B-46f6-B6F3-83FC294369A5}").ToLong(), "Public Interface", false, true);
			Db.PersistEntity(_csfPublicInfo);

			_csfDatabase = CreateSystemFeature(new Guid("{13588cda-d088-4344-91c6-27f382f7bf67}").ToLong(), "Database", false, true);
			Db.PersistEntity(_csfDatabase);

			_csfLan = CreateSystemFeature(new Guid("{01BD87D9-E767-4A71-9F2B-FAF164FB7F90}").ToLong(), "Internal Corporation Network", false, true);
			Db.PersistEntity(_csfLan);

			_csfAccounts = CreateSystemFeature(new Guid("CC173F15-6A93-4FEC-A583-5B93D9179427").ToLong(), "System Accounts", true, true);
			_csfAccounts.HackedOnly = true;
			Db.PersistEntity(_csfAccounts);

			_csfUsenet = CreateSystemFeature(new Guid("5BEE3EA9-35B1-4262-A4DE-2CCF329D2A81").ToLong(), "Usenet", false, true);
			Db.PersistEntity(_csfUsenet);

			_csfMissions = CreateSystemFeature(new Guid("1500F4D6-334A-402E-8C31-55FB32C9DC05").ToLong(), "Jobs", false, true);
			Db.PersistEntity(_csfMissions);

			ComputerSystemFeature csfHardwareStorage = CreateSystemFeature(new Guid("730F90CC-2E70-43AA-A013-103DCCC97729").ToLong(), "Hardware Storage", false, true);
			Db.PersistEntity(csfHardwareStorage);
			#endregion

			#region Bypassers
			Guid baseId = new Guid("9A5DDD79-FC55-481D-874F-146EDBABDA00");
			Guid bypasserId = baseId;

			for (int i = 1; i != 7; i++)
			{
				double speed = Math.Pow(7, i / 1.9);

				#region usernamepassword
				Bypasser bypUsernamePassword = CreateBypasser(
					bypasserId.ToLong(), new Guid("{B31E0242-C99F-4916-816C-E236EDDBF564}").ToLong(), "Password cracker", true, _ssUsernamePassword.Id, pcatSecurity,
					false, false, "BypassUsernamePassword", i*_ssUsernamePassword.DifficultyIdentifier, i, speed*3, SpeedType.Cpu, 700*i);
				Db.PersistEntity(bypUsernamePassword);
				#endregion

				#region fingerprint
				bypasserId = bypasserId.Increment();
				Bypasser bypFingerprint = CreateBypasser(
					bypasserId.ToLong(), new Guid("{631BA241-8E28-4eb8-9D6C-167134E00B64}").ToLong(), "Fingerprint spoofer", true, _ssFingerprintAuthentication.Id, pcatSecurity,
					false, false, "BypassFingerprint", i*_ssFingerprintAuthentication.DifficultyIdentifier, i, speed*4, SpeedType.Cpu, 800*i);
				Db.PersistEntity(bypFingerprint);
				#endregion

				#region retina
				bypasserId = bypasserId.Increment();
				Bypasser bypRetina = CreateBypasser(
					bypasserId.ToLong(), new Guid("E906A2D2-B07D-432F-8F87-BA26249E7ED5").ToLong(), "Retinal Scan bypass", true, _ssRetinalScan.Id, pcatSecurity,
					false, false, "BypassRetinal", i * _ssRetinalScan.DifficultyIdentifier, i, speed * 5, SpeedType.Cpu, 900 * i);
				Db.PersistEntity(bypRetina);
				#endregion

				#region DNA
				bypasserId = bypasserId.Increment();
				Bypasser bypDna = CreateBypasser(
					bypasserId.ToLong(), new Guid("9788AE4C-1746-4C20-A0E9-764977B15072").ToLong(), "DNA Profile bypass", true, _ssDna.Id, pcatSecurity,
					false, false, "BypassDNA", i * _ssDna.DifficultyIdentifier, i, speed * 6, SpeedType.Cpu, 1000 * i);
				Db.PersistEntity(bypDna);
				#endregion

				#region PSEC
				bypasserId = bypasserId.Increment();
				Bypasser bypPsec = CreateBypasser(
					bypasserId.ToLong(), new Guid("E9ECCE7B-3728-43DC-AAAD-5F6002A386A1").ToLong(), "PSEC bypass", true, _ssPsec.Id, pcatSecurity,
					false, false, "BypassPSEC", i * _ssPsec.DifficultyIdentifier, i, speed * 7, SpeedType.Cpu, 1200 * i);
				Db.PersistEntity(bypPsec);
				#endregion

				#region TBPA
				bypasserId = bypasserId.Increment();
				Bypasser bypTbpa = CreateBypasser(
					bypasserId.ToLong(), new Guid("1BF176C0-1876-4908-8909-E344A96360E3").ToLong(), "Brain Pattern bypass", true, _ssTbpa.Id, pcatSecurity, 
					false, false, "BypassTBPA", i * _ssTbpa.DifficultyIdentifier, i, speed * 8, SpeedType.Cpu, 1300 * i);
				Db.PersistEntity(bypTbpa);
				#endregion
			}

			#endregion

			#region Programs

			Program progCopyFile = CreateProgram(new Guid("42E1B7C2-ACB4-44DC-8740-74CF41B2BD63").ToLong(), new Guid("{825DF624-17A8-49ba-A9F2-3ED87F33C4D0}").ToLong(), "File Copying Tool", pcatFilesystem, true, false, true, 1,
			                                     2.0, SpeedType.Bandwidth, 1, 0, "CopyFile");
			Db.PersistEntity(progCopyFile);

			Program progDigitizeFingerprint = CreateProgram(new Guid("8761E160-DAED-4651-B1FB-3BF652B4F9E5").ToLong(), new Guid("410FD91E-053D-4EC0-9FED-4AE59C8A7245").ToLong(), "Personal finger print digitizer", pcatSecurity,
			                                                true, false, true, 1, 1, SpeedType.Cpu, 1, 100, "DigitizeFingerprint");
			Db.PersistEntity(progDigitizeFingerprint);

			Program progDigitizeRetina = CreateProgram(new Guid("71029C44-0C71-400C-AAF5-509BC582C840").ToLong(), new Guid("C13FB98E-4FC0-4CE9-92C3-F306C9283213").ToLong(), "Personal retinal digitizer", pcatSecurity,
			                                           true, false, false, 1, 1, SpeedType.Cpu, 1, 500, "DigitizeRetina");
			Db.PersistEntity(progDigitizeRetina);

			Program progDigitizeDna = CreateProgram(new Guid("A6FB12AB-C435-400F-8078-C975D7289E3F").ToLong(), new Guid("9DE16D8C-E6C5-4A79-9F5F-EFB3B838558E").ToLong(), "Personal DNA digitizer", pcatSecurity,
			                                        true, false, false, 1, 1, SpeedType.Cpu, 1, 1000, "DigitizeDNA");
			Db.PersistEntity(progDigitizeDna);

			baseId = new Guid("784A829F-BA00-4E5C-852B-22EA4F7B2B00");
			Guid programId = baseId;
			for (int i = 1; i != 7; i++)
			{
				double speed = Math.Pow(7, i/1.9);
#pragma warning disable 168
				bool isDefault = false;
#pragma warning restore 168
				int iterationSize = (int)Math.Ceiling(Math.Pow(i + 1.5, 1.75));

				Program progDeleteFile = CreateProgram(programId.ToLong(), new Guid("{4E4C855D-6B60-42eb-B3A2-CBC3D5E0BD7D}").ToLong(), "File Deleter", pcatFilesystem, true, false,
				                                       i == 1 ? true : false, iterationSize, speed * 3, SpeedType.Cpu, i, i*200, "DeleteFile");
				Db.PersistEntity(progDeleteFile);

				programId = programId.Increment();
				Program progUndeleteFile = CreateProgram(programId.ToLong(), new Guid("B29933BA-BE0E-4396-B53F-0661D46AE4F4").ToLong(), "File Undelete", pcatFilesystem, true, false,
				                                         false, iterationSize, speed * 3, SpeedType.Cpu, i, i * 200, "UndeleteFile");
				Db.PersistEntity(progUndeleteFile);

				programId = programId.Increment();
				Program progCompressFile = CreateProgram(programId.ToLong(), new Guid("{FDE1C8DE-2BF7-4e5a-8B3D-BC4D7DB015E3}").ToLong(), "File Compressor", pcatFilesystem, true, false,
				                                         false, iterationSize, speed*5, SpeedType.Cpu, i, i*200, "CompressFile");
				Db.PersistEntity(progCompressFile);

				programId = programId.Increment();
				Program progDecompressFile = CreateProgram(programId.ToLong(), new Guid("{02054403-29C6-4aad-97F1-54E7D39AC484}").ToLong(), "File Decompressor", pcatFilesystem, true, false,
				                                           false, iterationSize, speed * 5, SpeedType.Cpu, i, i * 200, "DecompressFile");
				Db.PersistEntity(progDecompressFile);

				programId = programId.Increment();
				Program progEncryptFile = CreateProgram(programId.ToLong(), new Guid("{9B141E05-3137-460e-999C-C4340E29533B}").ToLong(), "File Encrypter", pcatFilesystem, true, false,
				                                        false, iterationSize, speed * 5, SpeedType.Cpu, i, i * 200, "EncryptFile");
				Db.PersistEntity(progEncryptFile);

				programId = programId.Increment();
				Program progDecryptFile = CreateProgram(programId.ToLong(), new Guid("{898DC635-D75E-466e-9887-3440E228DFEF}").ToLong(), "File Decrypter", pcatFilesystem, true, false,
				                                        false, iterationSize, speed * 5, SpeedType.Cpu, i, i * 200, "DecryptFile");
				Db.PersistEntity(progDecryptFile);

				programId = programId.Increment();
				Program progCreateRainbowTableFile = CreateProgram(programId.ToLong(), new Guid("{EA122BCE-A6F9-44CD-817E-7363DF40CA0F}").ToLong(), "Rainbow Table Creator", pcatFilesystem, true, false, 
				                                                   false, iterationSize, speed * 5.5, SpeedType.Cpu, i, i * 200, "CreateRainbowTable");
				Db.PersistEntity(progCreateRainbowTableFile);

				programId = programId.Increment();
				Program progDeleteLog = CreateProgram(programId.ToLong(), new Guid("358A7986-10B1-4DC6-8470-13FC56855635").ToLong(), "Log deleter", pcatLogging, true, false,
				                                      false, iterationSize, speed * 3, SpeedType.Cpu, i, i * 200, "DeleteLog");
				Db.PersistEntity(progDeleteLog);

				programId = programId.Increment();
				Program progRestoreLog = CreateProgram(programId.ToLong(), new Guid("2725758F-17DF-41DC-847D-FD80BA4AF95B").ToLong(), "Log undeleter", pcatLogging, true, false,
				                                       false, iterationSize, speed * 3, SpeedType.Cpu, i, i * 200, "UndeleteLog");
				Db.PersistEntity(progRestoreLog);
			}
			//todo: add more programs as we go.

			#endregion

			#region Create all corporation systems

			//FOREACH corporation create 5 systems with increasing difficulty. 
			//Total Resulting data: 5000 computer systems, 75.000 accounts, 75.000 email accounts (?), 75.000 bank accounts
			//this is for virtual persons only.
			//{
			CreatePrerequisiteSystems();
			corps.GetRange(0, 20).ForEach(CreateCompanySystems);
			//corps.ForEach(CreateCompanySystems);
			Db.Commit();

			PointD adminPoint1 = _coordinator.GetFreeRandomGridpoint(adminCorp.Id);
			byte adminClassD = 0x01;
			NetworkAddress adminNwa1 = CreateNetworkAddress(new Guid("F802EAAA-2AC6-467B-8B68-7AA924C54241").ToLong(), 0x01, 0x01, 0x01, adminClassD++);
			ComputerSystem adminGateway = GetEntity<ComputerSystem>(new Guid("E8E035C4-989D-4936-872E-F3AB6462EA44").ToLong());
			adminGateway.ComputerSystemFeatures = adminGateway.ComputerSystemFeatures ?? new List<ComputerSystemFeature>();
			adminGateway.Name = "External Gateway";
			adminGateway.Corporation = adminGateway.Corporation ?? adminCorp;
			adminGateway.ComputerSystemLogs = adminGateway.ComputerSystemLogs ?? new List<ComputerSystemLog>();
			adminGateway.MapX = adminGateway.MapX == 0 ? adminPoint1.X : adminGateway.MapX;
			adminGateway.MapY = adminGateway.MapY == 0 ? adminPoint1.Y : adminGateway.MapY;
			adminGateway.SecuritySystem = adminGateway.SecuritySystem ?? new List<SecuritySystem>();
			adminGateway.Accounts = adminGateway.Accounts ?? new List<ComputerSystemAccount>();
			adminGateway.MaintenanceInterval = 0;
			adminGateway.NetworkAddress = adminNwa1;
			adminGateway.RootDirectory = adminGateway.RootDirectory ?? new SystemDirectory{Id = Guid.NewGuid().ToLong()};
			adminGateway.IsGatewayCentral = true;
			adminGateway.DifficultyLevel = 5;
			adminGateway.TrustedConnectionOnly = true;
			adminGateway.IsGatewayCentral = true;
			Db.PersistEntity(adminGateway);

			PointD adminPoint2 = _coordinator.GetFreeRandomGridpoint(adminCorp.Id);
			NetworkAddress adminNwa2 = CreateNetworkAddress(new Guid("54FC65BB-AF9A-43F8-A271-9F3F974486A4").ToLong(), 0x01, 0x01, 0x01, adminClassD++);

			ComputerSystem adminInternalServices = GetEntity<ComputerSystem>(new Guid("33A765B9-84F0-4CD1-BFC0-0ADA2F7C466A").ToLong());
			adminInternalServices.ComputerSystemFeatures = adminInternalServices.ComputerSystemFeatures ?? new List<ComputerSystemFeature> {_csfChat, _csfEmail, _csfMarket, _csfBanking, _csfFileView, _csfLogView, _csfLan, _csfAccounts};
			adminInternalServices.Accounts = adminInternalServices.Accounts ?? new List<ComputerSystemAccount>();
			adminInternalServices.AlwaysInvisible = false;
			adminInternalServices.ComputerSystemLogs = adminInternalServices.ComputerSystemLogs ?? new List<ComputerSystemLog>();
			adminInternalServices.Corporation = adminGateway.Corporation;
			adminInternalServices.DifficultyLevel = 4;
			adminInternalServices.IsGatewayCentral = false;
			adminInternalServices.IsDefaultBankServer = true;
			adminInternalServices.IsDefaultEmailServer = true;
			adminInternalServices.MaintenanceInterval = 0;
			adminInternalServices.MapX = adminInternalServices.MapX == 0 ? adminPoint2.X : adminInternalServices.MapX;
			adminInternalServices.MapY = adminInternalServices.MapY == 0 ? adminPoint2.Y : adminInternalServices.MapY;
			adminInternalServices.Name = "Internal Services";
			adminInternalServices.NetworkAddress = adminInternalServices.NetworkAddress ?? adminNwa2;
			adminInternalServices.RootDirectory = adminInternalServices.RootDirectory ?? new SystemDirectory {Id = Guid.NewGuid().ToLong()};
			adminInternalServices.SecuritySystem = adminInternalServices.SecuritySystem ?? new List<SecuritySystem>();
			adminInternalServices.TrustedConnectionOnly = false;

			Db.PersistEntity(adminInternalServices);

			BankAccount adminBank = GetEntity<BankAccount>(new Guid("68E7004A-D4C8-4589-8CF4-52E5982388B4").ToLong());
			adminBank.AccountNumber = Utils.GetBankAccountNumber(Db, adminInternalServices.Id);
			adminBank.CachedAmount = 0;
			adminBank.IsInvisible = true;
			adminBank.IsSystem = true;
			adminBank.SystemId = adminInternalServices.Id;
			Db.PersistEntity(adminBank);
			Db.Commit();

			#endregion

			CreateHardware();

			#region Admin accounts
			NetworkAddress nwa1 = CreateNetworkAddress(new Guid("DF20C9BA-EE77-434F-B99A-9DF5591C0568").ToLong(), 0x01, 0x01, 0x01, adminClassD++);
			Account account1 = CreateNewAgentAccount(new Guid("8C2E5C8D-71AA-49DF-939C-9BBAD0A9954F").ToLong(), "root", "test".EncryptPassword(), "r00t", adminCorp, nwa1, true);
			BankAccount ba1 = GetEntity<BankAccount>(new Guid("E2F17888-6AA9-4685-A87C-5213D217685D").ToLong());
			if (ba1.AccountNumber == 0)
			{
				ba1.AccountNumber = Utils.GetBankAccountNumber(Db, adminInternalServices.Id);
				ba1.SystemId = adminInternalServices.Id;
				BankTransaction bat1 = GetEntity<BankTransaction>(new Guid("EDF59119-85C8-414B-B3E1-7E8F76314DCB").ToLong());
				if (bat1.ReceivingAccountId == 0)
				{
					bat1.Amount = 150000000;
					bat1.Purpose = "Admin budget";
					bat1.ReceivingAccountId = ba1.Id;
					bat1.SendingAccountId = adminBank.Id;
					bat1.TransactionTimeStamp = DateTime.Now;
					Db.PersistEntity(bat1);
					account1.Agent.BankAccounts.Add(ba1);
				}
			}
			EmailAccount ea = GetEntity<EmailAccount>(new Guid("D8074B51-CEDB-473A-8E4B-F75EF211707B").ToLong());
			ea.Name = "r00t";
			ea.SystemId = adminInternalServices.Id;
			account1.Agent.EmailAccounts.Add(ea);
			UsenetAccount una = GetEntity<UsenetAccount>(new Guid("5B7994E5-4FEC-48D3-92AB-54807E6DAC3F").ToLong());
			una.AccountStatus = UsenetAccountStatus.Active;
			una.IsAdmin = true;
			una.EmailAccountId = ea.Id;
			account1.Agent.UsenetAccount = una;
			Db.PersistEntity(account1);

			NetworkAddress nwa2 = CreateNetworkAddress(new Guid("F065BA53-45BE-4407-9074-0C4A21AB676E").ToLong(), 0x01, 0x01, 0x01, adminClassD);
			Account account2 = CreateNewAgentAccount(new Guid("D069BD23-5541-4D8C-819B-99DFCC7F6B76").ToLong(), "test", "test".EncryptPassword(), "Tester1", adminCorp, nwa2, true);
			var visibleSystems = (from ComputerSystem cs in Db where cs.AlwaysVisible || cs.Corporation == account2.Agent.Corporation select cs.Id).ToList();
			account2.Agent.ComputerSystemIds = visibleSystems;
			account2.AccountStatus = AccountStatus.Active;
			BankAccount ba2 = GetEntity<BankAccount>(new Guid("5EE8B411-F9E0-473F-A99E-16D5158FF668").ToLong());
			if (ba2.AccountNumber == 0)
			{
				ba2.AccountNumber = Utils.GetBankAccountNumber(Db, adminInternalServices.Id);
				ba2.SystemId = adminInternalServices.Id;
				BankTransaction bat2 = GetEntity<BankTransaction>(new Guid("A531154F-D8A4-43D9-BA70-E970BABB2D10").ToLong());
				bat2.Amount = 150000000;
				bat2.Purpose = "Admin budget";
				bat2.ReceivingAccountId = ba2.Id;
				bat2.SendingAccountId = adminBank.Id;
				bat2.TransactionTimeStamp = DateTime.Now;
				Db.PersistEntity(bat2);
				account2.Agent.BankAccounts.Add(ba2);
			}

			EmailAccount ea2 = GetEntity<EmailAccount>(new Guid("62849726-ED0B-46BF-9461-1ADEA7972D61").ToLong());
			ea2.Name = "test";
			ea2.SystemId = adminInternalServices.Id;
			account2.Agent.EmailAccounts.Add(ea2);
			UsenetAccount una2 = GetEntity<UsenetAccount>(new Guid("83362EE7-AAF0-41A0-B5B5-98041A0B3FDB").ToLong());
			una2.AccountStatus = UsenetAccountStatus.Active;
			una2.IsAdmin = true;
			una2.EmailAccountId = ea2.Id;
			account2.Agent.UsenetAccount = una2;
			Db.PersistEntity(account2);
			#endregion
			
			DistributeCredentialFiles();

			Db.Commit();
			sw.Stop();
			if (OperationCompleted != null)
				OperationCompleted(this, null);
		}
	}
}